home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / smaltalk / gnu_st.lha / gnu_st / smalltalk-1.1.1 / mstsave.c < prev    next >
C/C++ Source or Header  |  1991-09-12  |  21KB  |  893 lines

  1. /***********************************************************************
  2.  *
  3.  *    Binary image save/restore.
  4.  *
  5.  ***********************************************************************/
  6.  
  7. /***********************************************************************
  8.  *
  9.  * Copyright (C) 1990, 1991 Free Software Foundation, Inc.
  10.  * Written by Steve Byrne.
  11.  *
  12.  * This file is part of GNU Smalltalk.
  13.  *
  14.  * GNU Smalltalk is free software; you can redistribute it and/or modify it
  15.  * under the terms of the GNU General Public License as published by the Free
  16.  * Software Foundation; either version 1, or (at your option) any later 
  17.  * version.
  18.  * 
  19.  * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
  20.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
  21.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  22.  * more details.
  23.  * 
  24.  * You should have received a copy of the GNU General Public License along with
  25.  * GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
  26.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  
  27.  *
  28.  ***********************************************************************/
  29.  
  30.  
  31. /*
  32.  *    Change Log
  33.  * ============================================================================
  34.  * Author      Date       Change 
  35.  * sbyrne    17 Apr 90      Fixing binary save to save only to the maximum used
  36.  *              OOP slot, instead of saving the entire OOP table.
  37.  *              This should improve load time and decrease disk
  38.  *              storage requirements.
  39.  *
  40.  * sbyrne    11 Feb 90      Changed the header to record the size of the oop
  41.  *              table, since trying to load back into a system with a
  42.  *              different sized oop table loses bigtime.
  43.  *
  44.  * sbyrne     5 Apr 89      modified to reflect change in classes: now their name
  45.  *              is a Smalltalk string; before, it was a C string that
  46.  *              had to be saved specially.
  47.  *
  48.  * sbyrne     4 Mar 89      Created.
  49.  *
  50.  */
  51.  
  52.  
  53. #include <stdio.h>
  54. #include "mst.h"
  55. #include "mstsave.h"
  56. #include "mstcomp.h"
  57. #include "mstinterp.h"
  58. #include "mstdict.h"
  59. #include "mstsym.h"
  60. #include "mstoop.h"        /* indirectly defines oopAt for sym tab prof */
  61. #include "mstmain.h"
  62. #ifdef HAS_ALLOCA_H
  63. #include <alloca.h>
  64. #endif
  65. #include <stdio.h>
  66.  
  67. #ifndef MAXPATHLEN
  68. #define MAXPATHLEN        1024 /* max length of a file and path */
  69. #endif
  70.  
  71. #define fromBeginning        0 /* symbolic name for file offset modifier */
  72.  
  73. /* convert to a relative offset from start of OOP table */
  74. #define toRelative(obj) \
  75.   ( (OOP)((long)(obj) - (long)oopTable) )
  76.  
  77. /* convert from relative offset to actual oop table address */
  78. #define fromRelative(obj) \
  79.   ( (OOP)((long)(obj) + (long)oopTable) )
  80.  
  81. /* round "x" up to the next 4 byte boundary */
  82. #define roundUpWord(x) \
  83.   ( ((x) + 3) & ~3 )
  84.  
  85. /*
  86.  * The binary image file has the following format:
  87.  *
  88.  *    header
  89.  *    complete oop table
  90.  *    global oop variable data
  91.  *    objects and non-oop object data
  92.  *    char object data
  93.  *    nil object
  94.  *    boolean objects
  95.  */
  96.  
  97.  
  98. typedef struct SaveFileHeaderStruct {
  99.   long        version;    /* the Smalltalk version that made this dump */
  100.   long        objectDataSize;    /* size of object data section in bytes */
  101.   long        oopTableSize;    /* size of the oop table at dump */
  102. } SaveFileHeader;
  103.  
  104. typedef struct OOPVectorStruct {
  105.   Object    base;        /* base of the storage */
  106.   Object    ptr;        /* the current object */
  107. } OOPVector;
  108.  
  109.  
  110. OOP        *globalOOPs[] = {
  111.   &andColonSymbol,
  112.   &atColonPutColonSymbol,
  113.   &atColonSymbol,
  114.   &atEndSymbol,
  115.   &bitAndColonSymbol,
  116.   &bitOrColonSymbol,
  117.   &bitShiftColonSymbol,
  118.   &blockCopyColonSymbol,
  119.   &classSymbol,
  120.   ÷Symbol,
  121.   &doColonSymbol,
  122.   &equalSymbol,
  123.   &greaterEqualSymbol,
  124.   &greaterThanSymbol,
  125.   &ifFalseColonIfTrueColonSymbol,
  126.   &ifFalseColonSymbol,
  127.   &ifTrueColonIfFalseColonSymbol,
  128.   &ifTrueColonSymbol,
  129.   &integerDivideSymbol,
  130.   &lessEqualSymbol,
  131.   &lessThanSymbol,
  132.   &minusSymbol,
  133.   &newColonSymbol,
  134.   &newSymbol,
  135.   &nextPutColonSymbol,
  136.   &nextSymbol,
  137.   ¬EqualSymbol,
  138.   ¬SameObjectSymbol,
  139.   &orColonSymbol,
  140.   &plusSymbol,
  141.   &remainderSymbol,
  142.   &sameObjectSymbol,
  143.   &sizeSymbol,
  144.   &thisContextSymbol,
  145.   ×Symbol,
  146.   &valueColonSymbol,
  147.   &valueColonValueColonSymbol,
  148.   &valueColonValueColonValueColonSymbol,
  149.   &valueWithArgumentsColonSymbol,
  150.   &valueSymbol,
  151.   &whileFalseColonSymbol,
  152.   &whileTrueColonSymbol,
  153.   &orSymbol,
  154.   &andSymbol,
  155.   &superSymbol,
  156.   &nilSymbol,
  157.   &trueSymbol,
  158.   &falseSymbol,
  159.   &selfSymbol,
  160.   &doesNotUnderstandColonSymbol,
  161.   &unknownSymbol,
  162.   &charSymbol,
  163.   &stringSymbol,
  164.   &stringOutSymbol, 
  165.   &symbolSymbol,
  166.   &intSymbol,
  167.   &longSymbol,
  168.   &doubleSymbol,
  169.   &voidSymbol,
  170.   &variadicSymbol,
  171.   &cObjectSymbol,
  172.   &smalltalkSymbol,
  173.   &byteArraySymbol,
  174.   &objectClass,
  175.   &magnitudeClass,
  176.   &charClass,
  177.   &timeClass,
  178.   &numberClass,
  179.   &floatClass,
  180.   &integerClass,
  181.   &lookupKeyClass,
  182.   &associationClass,
  183.   &linkClass,
  184.   &processClass,
  185.   &symLinkClass,
  186.   &collectionClass,
  187.   &sequenceableCollectionClass,
  188.   &linkedListClass,
  189.   &semaphoreClass,
  190.   &arrayedCollectionClass,
  191.   &arrayClass,
  192.   &stringClass,
  193.   &symbolClass,
  194.   &byteArrayClass,
  195.   &compiledMethodClass,
  196.   &intervalClass,
  197.   &orderedCollectionClass,
  198.   &sortedCollectionClass,
  199.   &bagClass,
  200.   &mappedCollectionClass,
  201.   &setClass,
  202.   &dictionaryClass,
  203.   &identityDictionaryClass,
  204.   &systemDictionaryClass,
  205.   &undefinedObjectClass,
  206.   &booleanClass,
  207.   &falseClass,
  208.   &trueClass,
  209.   &processorSchedulerClass,
  210.   &delayClass,
  211.   &sharedQueueClass,
  212.   &behaviorClass,
  213.   &classDescriptionClass,
  214.   &classClass,
  215.   &metaclassClass,
  216.   &smalltalkDictionary,
  217.   &messageClass,
  218.   &methodContextClass,
  219.   &blockContextClass,
  220.   &streamClass,
  221.   &positionableStreamClass,
  222.   &readStreamClass,
  223.   &writeStreamClass,
  224.   &readWriteStreamClass,
  225.   &cObjectClass,
  226.   &fileStreamClass,
  227.   &memoryClass,
  228.   &byteMemoryClass,
  229.   &wordMemoryClass,
  230.   &randomClass,
  231.   &cFuncDescriptorClass,
  232.   &tokenStreamClass,
  233.   &methodInfoClass,
  234.   &fileSegmentClass,
  235.   &nilOOP,
  236.   &trueOOP,
  237.   &falseOOP,
  238.   &processorOOP,
  239.   &symbolTable,
  240.   nil
  241. };
  242.  
  243.  
  244. static void    skipOverHeader(), saveObject(), fixupObject(),
  245.         fixupMethodObject(), restoreObject(), restoreMethodObject(),
  246.         saveOOPTable(), fixupAllOOPs(), fixupOOP(),
  247.         /* fixupFreeOOP(), */restoreAllOOPs(), restoreOOP(), 
  248.         /*restoreFreeOOP(), */loadOOPTable(), loadNormalOOPs(),
  249.         loadCharOOPs(), loadSpecialOOPs(), saveGlobalOOPs(),
  250.         loadGlobalOOPs(), fixupClassObject(), restoreInstanceVars(),
  251.         restoreClassObject(), saveFileVersion(),
  252.         loadFileVersion(), fixupInstanceVars(), fixupOOPInstanceVars();
  253.  
  254. static int    saveNormalOOPs(), saveAllObjects();
  255.  
  256.  
  257. /* This variable contains the OOP slot index of the highest non-free OOP,
  258.  * excluding the built-in ones (i.e., it will always be < OOP_TABLE_SIZE).
  259.  * This is used for optimizing the size of the saved image, and minimizing
  260.  * the load time when restoring the system. */
  261. static int    maxUsedOOPSlot = 0;
  262.  
  263.  
  264. Boolean saveToFile(fileName)
  265. char    *fileName;
  266. {
  267.   FILE        *imageFile;
  268.   long        objectDataSize;
  269.   Boolean    oldGCState;
  270.  
  271.   fullGC();            /* make sure that the world is compact if
  272.                    possible */
  273.  
  274.   oldGCState = gcOff();
  275.  
  276. #ifdef BINARY_MODE_NEEDED
  277.   imageFile = fopen(fileName, "wb");
  278. #else
  279.   imageFile = fopen(fileName, "w");
  280. #endif
  281.   if (imageFile == NULL) {
  282.     errorf("Couldn't open file %s", fileName);
  283.     return (false);
  284.   }
  285.  
  286.   skipOverHeader(imageFile);
  287.   saveOOPTable(imageFile);
  288.  
  289. #ifdef OOP_TABLE_TRACE
  290. printf("After saving oopt table: %d\n", ftell(imageFile));
  291. #endif /* OOP_TABLE_TRACE */
  292.  
  293.   saveGlobalOOPs(imageFile);
  294.  
  295. #ifdef OOP_TABLE_TRACE
  296. printf("After global oop table: %d\n", ftell(imageFile));
  297. #endif /* OOP_TABLE_TRACE */
  298.  
  299.   objectDataSize = saveAllObjects(imageFile);
  300.  
  301. #ifdef OOP_TABLE_TRACE
  302. printf("After saving all objects table: %d\n", ftell(imageFile));
  303. #endif /* OOP_TABLE_TRACE */
  304.  
  305.   skipToHeader(imageFile);
  306.   saveFileVersion(imageFile, objectDataSize);
  307.  
  308.   fclose(imageFile);
  309.  
  310.   setGCState(oldGCState);
  311.   return (true);
  312.  
  313.  
  314. static void skipOverHeader(imageFile)
  315. FILE    *imageFile;
  316. {
  317.   unsigned long    pos;
  318.  
  319.   fseek(imageFile, sizeof(SaveFileHeader), fromBeginning);
  320. }
  321.  
  322. /*
  323.  *    static void saveOOPTable(imageFile)
  324.  *
  325.  * Description
  326.  *
  327.  *    Writes the OOP table out to the image file.  We need to make all
  328.  *    of the object pointers relative, including free OOP table slots, and
  329.  *    we use a parallel vector containing file offsets for the objects that
  330.  *    we developed during saving of the objects themselves as the fixup
  331.  *    table.
  332.  *
  333.  * Inputs
  334.  *
  335.  *    imageFile: 
  336.  *        A stdio FILE to be written to.  It must be positioned
  337.  *        correctly before this routine is called.
  338.  *
  339.  */
  340. static void saveOOPTable(imageFile)
  341. FILE    *imageFile;
  342. {
  343.   fixupAllOOPs();
  344.  
  345. #ifdef OOP_TABLE_TRACE
  346. printf("there are %d free oops out of %d oops, leaving %d\n",
  347.        numFreeOOPs, OOP_TABLE_SIZE, OOP_TABLE_SIZE - numFreeOOPs);
  348. printf("max used is %d\n", maxUsedOOPSlot);
  349. #endif /* OOP_TABLE_TRACE */
  350.  
  351.   /* save up to the max oop slot in use */
  352.   fwrite(oopTable, sizeof(struct OOPStruct), maxUsedOOPSlot + 1, imageFile);
  353.  
  354.   /* then save the constant ones at the end */
  355.   fwrite(&oopTable[OOP_TABLE_SIZE], sizeof(struct OOPStruct),
  356.      TOTAL_OOP_TABLE_SLOTS - OOP_TABLE_SIZE, imageFile);
  357.  
  358.   restoreAllOOPs();
  359. }
  360.  
  361.  
  362. static void fixupAllOOPs()
  363. {
  364.   int        i;
  365.  
  366.   maxUsedOOPSlot = 0;
  367.  
  368.   for (i = 0; i < TOTAL_OOP_TABLE_SLOTS; i++) {
  369.     fixupOOP(i);
  370.   }
  371. }
  372.  
  373. static void fixupOOP(i)
  374. int    i;
  375. {
  376.   OOP        oop;
  377.  
  378.   oop = oopAt(i);
  379. #ifdef old_code /* Tue Apr 17 22:48:45 1990 */
  380. /**/  if (oop->isFree) {
  381. /**/    fixupFreeOOP(oop);
  382. /**/  } else {
  383. #endif /* old_code Tue Apr 17 22:48:45 1990 */
  384.   if (!oop->isFree) {
  385.     if (i < OOP_TABLE_SIZE) {
  386.       maxUsedOOPSlot = i;
  387.     }
  388.     oop->object = (Object)toRelative(oop->object);
  389.   }
  390. }
  391.  
  392. #ifdef old_code /* Tue Apr 17 22:49:42 1990 */
  393. /**/
  394. /**/static void fixupFreeOOP(oop)
  395. /**/OOP    oop;
  396. /**/{
  397. /**/  if (oop->object == nil) {
  398. /**/    oop->object = (Object)-1L;
  399. /**/  } else {
  400. /**/    oop->object = (Object)toRelative(oop->object);
  401. /**/  }
  402. /**/
  403. /**/  oop->isFree = 0;
  404. /**/  if (oop->prevFree == (long)nil) {
  405. /**/    oop->prevFree = -1L;
  406. /**/  } else {
  407. /**/    oop->prevFree = (long)toRelative(oop->prevFree);
  408. /**/  }
  409. /**/
  410. /**/  oop->isFree = 1;
  411. /**/}
  412. #endif /* old_code Tue Apr 17 22:49:42 1990 */
  413.  
  414.  
  415. static void restoreAllOOPs()
  416. {
  417.   int        i;
  418.  
  419.   for (i = 0; i < TOTAL_OOP_TABLE_SLOTS; i++) {
  420.     restoreOOP(i);
  421.   }
  422. }
  423.  
  424.  
  425.  
  426. static void restoreOOP(i)
  427. int    i;
  428. {
  429.   OOP        oop;
  430.  
  431.   oop = oopAt(i);
  432. #ifdef old_code /* Tue Apr 17 22:50:19 1990 */
  433. /**/  if (oop->isFree) {
  434. /**/    restoreFreeOOP(oop);
  435. /**/  } else {
  436. #endif /* old_code Tue Apr 17 22:50:19 1990 */
  437.   if (!oop->isFree) {
  438.     oop->object = (Object)fromRelative(oop->object);
  439.   }
  440. }
  441.  
  442. #ifdef old_code /* Tue Apr 17 22:50:39 1990 */
  443. /**/static void restoreFreeOOP(oop)
  444. /**/OOP    oop;
  445. /**/{
  446. /**/  if (oop->object == (Object)-1L) {
  447. /**/    oop->object = nil;
  448. /**/  } else {
  449. /**/    oop->object = (Object)fromRelative(oop->object);
  450. /**/  }
  451. /**/
  452. /**/  if (oop->prevFree == -1L) {
  453. /**/    oop->prevFree = (long)nil;
  454. /**/  } else {
  455. /**/    oop->isFree = 0;
  456. /**/    oop->prevFree = (long)fromRelative(oop->prevFree);
  457. /**/  }
  458. /**/
  459. /**/  oop->isFree = 1;
  460. /**/}
  461. #endif /* old_code Tue Apr 17 22:50:39 1990 */
  462.  
  463.  
  464. static void saveGlobalOOPs(imageFile)
  465. FILE    *imageFile;
  466. {
  467.   OOP        **oopPtr, oop;
  468.  
  469.   for (oopPtr = globalOOPs; *oopPtr; oopPtr++) {
  470.     oop = toRelative(**oopPtr);
  471.     fwrite(&oop, sizeof(OOP), 1, imageFile);
  472.   }
  473. }
  474.  
  475.  
  476. static int saveAllObjects(imageFile)
  477. FILE    *imageFile;
  478. {
  479.   long        objectStart, objectEnd;
  480.   int        i;
  481.   OOP        oop;
  482.  
  483.   objectStart = ftell(imageFile);
  484.   for (i = 0; i < OOP_TABLE_SIZE; i++) {
  485.     oop = oopAt(i);
  486.     if (oopValid(oop)) {
  487.       saveObject(imageFile, oop);
  488.     }
  489.   }
  490.  
  491.   objectEnd = ftell(imageFile);
  492.  
  493.   /* dump out the character objects, nil, true, and false */
  494.   for (i = OOP_TABLE_SIZE; i < TOTAL_OOP_TABLE_SLOTS; i++) {
  495.     saveObject(imageFile, oopAt(i));
  496.   }
  497.  
  498.   return (objectEnd - objectStart);
  499. }
  500.  
  501. static void saveObject(imageFile, oop)
  502. FILE    *imageFile;
  503. OOP    oop;
  504. {
  505.   Object    object;
  506.   int        numFixed, numIndexed;
  507.   Boolean    hasPointers;
  508.  
  509.   object = oopToObj(oop);
  510.   hasPointers = isPointers(oop);
  511.   numFixed = oopFixedFields(oop);
  512.   numIndexed = numIndexableFields(oop);
  513.  
  514.   fixupObject(oop, hasPointers, numFixed, numIndexed);
  515.   fwrite(object, sizeof(OOP), object->objSize, imageFile);
  516.   restoreObject(oop, hasPointers, numFixed, numIndexed);
  517. }
  518.  
  519. static void fixupObject(oop, hasPointers, numFixed, numIndexed)
  520. OOP    oop;
  521. Boolean    hasPointers;
  522. int    numFixed, numIndexed;
  523. {
  524.   int        i;
  525.   Object    object;
  526.   OOP        instOOP, classOOP;
  527.  
  528.   classOOP = oopClass(oop);
  529.  
  530.   if (classOOP == compiledMethodClass) {
  531.     fixupMethodObject(oop);
  532.   } else {
  533.     if (hasPointers) {
  534.       for (i = 1; i <= numFixed + numIndexed; i++) {
  535.     instOOP = instVarAt(oop, i);
  536.     if (!isInt(instOOP)) {
  537.       instVarAtPut(oop, i, toRelative(instOOP));
  538.     }
  539.       }
  540.     }
  541.   }
  542.  
  543.   object = oopToObj(oop);
  544.   object->objClass = toRelative(object->objClass);
  545. }
  546.  
  547. static void fixupMethodObject(oop)
  548. OOP    oop;
  549. {
  550.   MethodHeader    header;
  551.   int        i;
  552.   OOP        literalOOP, descriptorOOP;
  553.  
  554.   descriptorOOP = getMethodDescriptor(oop);
  555.   if (!isInt(descriptorOOP)) {
  556.     setMethodDescriptor(oop, toRelative(descriptorOOP));
  557.   }
  558.   header = getMethodHeaderExt(oop);
  559.   if (header.headerFlag == 1 || header.headerFlag == 2) {
  560.     /* these have no method literals to fix up, so we ignore them */
  561.     return;
  562.   }
  563.  
  564.   for (i = 0; i < header.numLiterals; i++) {
  565.     literalOOP = methodLiteralExt(oop, i);
  566.     if (!isInt(literalOOP)) {
  567.       storeMethodLiteralNoGC(oop, i, toRelative(literalOOP));
  568.     }
  569.   }
  570. }
  571.  
  572. static void restoreObject(oop, hasPointers, numFixed, numIndexed)
  573. OOP    oop;
  574. Boolean    hasPointers;
  575. int    numFixed, numIndexed;
  576. {
  577.   Object    object;
  578.  
  579.   object = oopToObj(oop);
  580.  
  581.   object->objClass = fromRelative(object->objClass);
  582.  
  583.   restoreInstanceVars(oop, hasPointers, numFixed, numIndexed);
  584. }
  585.  
  586. static void restoreInstanceVars(oop, hasPointers, numFixed, numIndexed)
  587. OOP    oop;
  588. Boolean    hasPointers;
  589. int    numFixed, numIndexed;
  590. {
  591.   register int    i;
  592.   OOP        instOOP, classOOP;
  593.  
  594.   classOOP = oopClass(oop);
  595.   if (classOOP == compiledMethodClass) {
  596.     restoreMethodObject(oop);
  597.   } else {
  598.     if (hasPointers) {
  599.       for (i = 1; i <= numFixed + numIndexed; i++) {
  600.     instOOP = instVarAt(oop, i);
  601.     if (!isInt(instOOP)) {
  602.       instVarAtPut(oop, i, fromRelative(instOOP));
  603.     }
  604.       }
  605.       if (classOOP == cFuncDescriptorClass) {
  606.     restoreCFuncDescriptor(oop); /* in mstcint.c */
  607.       }
  608.     }
  609.   }
  610. }
  611.  
  612. static void restoreMethodObject(oop)
  613. OOP    oop;
  614. {
  615.   MethodHeader    header;
  616.   int        i;
  617.   OOP        literalOOP, descriptorOOP;
  618.  
  619.   descriptorOOP = getMethodDescriptor(oop);
  620.   if (!isInt(descriptorOOP)) {
  621.     setMethodDescriptor(oop, fromRelative(descriptorOOP));
  622.   }
  623.  
  624.   header = getMethodHeaderExt(oop);
  625.   if (header.headerFlag == 1 || header.headerFlag == 2) {
  626.     /* these have no method literals to fix up, so we ignore them */
  627.     return;
  628.   }
  629.  
  630.   for (i = 0; i < header.numLiterals; i++) {
  631.     literalOOP = methodLiteralExt(oop, i);
  632.     if (!isInt(literalOOP)) {
  633.       storeMethodLiteralNoGC(oop, i, fromRelative(literalOOP));
  634.     }
  635.   }
  636. }
  637.  
  638.  
  639. skipToHeader(imageFile)
  640. FILE    *imageFile;
  641. {
  642.   rewind(imageFile);
  643. }
  644.  
  645. static void saveFileVersion(imageFile, objectDataSize)
  646. FILE    *imageFile;
  647. long    objectDataSize;
  648. {
  649.   SaveFileHeader header;
  650.  
  651.   header.version = sysVersMajor * 1000000 + sysVersMinor * 1000 + sysVersEdit;
  652.   header.objectDataSize = objectDataSize;
  653.   header.oopTableSize = maxUsedOOPSlot + 1; /* n slots, numbered 0..n-1 */
  654.  
  655.   fwrite(&header, sizeof(SaveFileHeader), 1, imageFile);
  656. }
  657.  
  658. static void skipToOOPTable(imageFile)
  659. FILE    *imageFile;
  660. {
  661.   rewind(imageFile);
  662. }
  663.  
  664.  
  665. /***********************************************************************
  666.  *
  667.  *    Binary loading routines.
  668.  *
  669.  ***********************************************************************/
  670.  
  671.  
  672. Boolean loadFromFile(fileName)
  673. char    *fileName;
  674. {
  675.   FILE        *imageFile;
  676.   SaveFileHeader header;
  677.   OOPVector    ov;
  678.   Boolean    oldGCState;
  679.   char        fullImageName[MAXPATHLEN];
  680.  
  681.   oldGCState = gcOff();
  682.  
  683.   findImageFile(fileName, fullImageName);
  684. #ifdef BINARY_MODE_NEEDED
  685.   imageFile = fopen(fullImageName, "rb");
  686. #else
  687.   imageFile = fopen(fullImageName, "r");
  688. #endif
  689.   if (imageFile == NULL) {
  690.     return (false);
  691.   }
  692.  
  693.   loadFileVersion(imageFile, &header);
  694.   if (header.version != (sysVersMajor * 1000000 + sysVersMinor * 1000
  695.              + sysVersEdit)) {
  696.     /* version mismatch; this image file is invalid */
  697.     return (false);
  698.   }
  699.   
  700. #ifdef old_code /* Tue Apr 17 22:25:33 1990 */
  701. /**/  if (header.oopTableSize != OOP_TABLE_SIZE) {
  702. /**/    return (false);
  703. /**/  }
  704. #endif /* old_code Tue Apr 17 22:25:33 1990 */
  705.  
  706.   loadOOPTable(imageFile, header.oopTableSize);
  707.  
  708.   loadGlobalOOPs(imageFile);
  709.  
  710.   loadNormalOOPs(imageFile, header.objectDataSize, &ov);
  711.   loadCharOOPs(imageFile);
  712.   loadSpecialOOPs(imageFile);
  713.  
  714.   fixupInstanceVars(&ov);
  715.  
  716.   fclose(imageFile);
  717.  
  718.   setGCState(oldGCState);
  719.  
  720.   return (true);
  721. }
  722.  
  723. static void loadFileVersion(imageFile, headerp)
  724. FILE    *imageFile;
  725. SaveFileHeader *headerp;
  726. {
  727.   fread(headerp, sizeof(SaveFileHeader), 1, imageFile);
  728. }
  729.  
  730. static void loadOOPTable(imageFile, oldSlotsUsed)
  731. FILE    *imageFile;
  732. long     oldSlotsUsed;
  733. {
  734.   long        i;
  735.   OOP        oop;
  736.  
  737. /*  fread(oopTable, sizeof(struct OOPStruct), TOTAL_OOP_TABLE_SLOTS, imageFile);*/
  738.  
  739.   /* load in the valid OOP slots from previous dump */
  740.   fread(oopTable, sizeof(struct OOPStruct), oldSlotsUsed, imageFile);
  741.   
  742.   /* mark the remaining ones as available */
  743.   for (i = oldSlotsUsed; i < OOP_TABLE_SIZE; i++) {
  744.     oop = oopAt(i);
  745.     oop->isFree = true;
  746.   }
  747.  
  748.  
  749.   /* read in the constant stuff at the end */
  750.   fread(&oopTable[OOP_TABLE_SIZE], sizeof(struct OOPStruct),
  751.     TOTAL_OOP_TABLE_SLOTS - OOP_TABLE_SIZE, imageFile);
  752.  
  753.   /* the fixup gets handled by load normal oops */
  754. }
  755.  
  756.  
  757. static void loadGlobalOOPs(imageFile)
  758. FILE    *imageFile;
  759. {
  760.   OOP        **oopPtr, oop, *oopVec;
  761.   long        numGlobalOOPs;
  762.  
  763.   for (numGlobalOOPs = 0, oopPtr = globalOOPs; *oopPtr;
  764.        oopPtr++, numGlobalOOPs++);
  765.  
  766.   oopVec = (OOP *)alloca(numGlobalOOPs * sizeof(OOP));
  767.   fread(oopVec, sizeof(OOP), numGlobalOOPs, imageFile);
  768.  
  769.   for (oopPtr = globalOOPs; *oopPtr; oopPtr++, oopVec++) {
  770.     **oopPtr = fromRelative(*oopVec);
  771.   }
  772. #ifdef old_code /* Wed Apr 26 21:15:38 1989 */ /* <<<== what dedication...3 days before my wedding -- SBB */
  773. /**/  /* ??? this could be sped up by using alloca, doing one fread, and then
  774. /**/     iterating through the array */
  775. /**/  for (oopPtr = globalOOPs; *oopPtr; oopPtr++) {
  776. /**/    fread(&oop, sizeof(OOP), 1, imageFile);
  777. /**/    **oopPtr = fromRelative(oop);
  778. /**/  }
  779. #endif /* old_code Wed Apr 26 21:15:38 1989 */
  780. }
  781.  
  782. static void loadNormalOOPs(imageFile, objectDataSize, ovp) 
  783. FILE    *imageFile;
  784. long    objectDataSize;
  785. OOPVector *ovp;
  786. {
  787.   register long    i;
  788.   OOP        oop, prevFreeOOP;
  789.   Object    object, objPtr;
  790.  
  791.   objPtr = curSpaceAddr();
  792.  
  793.   ovp->base = objPtr;
  794.  
  795.   prevFreeOOP = nil;
  796.  
  797.   fread(objPtr, 1, objectDataSize, imageFile);
  798.  
  799.   freeOOPs = nil;
  800.   numFreeOOPs = 0;
  801.   for (i = 0; i < OOP_TABLE_SIZE; i++) {
  802.     oop = oopAt(i);
  803.     if (oopValid(oop)) {
  804.       object = objPtr;
  805.       oop->object = object;
  806.       /* ### should probably make this setting symbolic/abstracted */
  807.       oop->inSpace = toSpace;
  808.       oop->oddMark = toSpace;
  809.       oop->evenMark = !toSpace;
  810.       object->objClass = fromRelative(object->objClass);
  811.       objPtr = (Object)((long *)object + object->objSize);
  812.     } else if (oop->isFree) {    /* ignore non-free but non-valid...they'll get handled
  813.                    naturally in due time. */
  814.       numFreeOOPs++;
  815.       if (prevFreeOOP) {    /* forward chain the oop free list */
  816.     prevFreeOOP->object = (Object)oop;
  817.       }
  818.       if (freeOOPs == nil) {    /* free list points at first free oop in
  819.                    OOP table */
  820.     freeOOPs = oop;
  821.       }
  822.       prevFreeOOP = oop;
  823.     }
  824.   }
  825.  
  826.   if (prevFreeOOP) {
  827.     prevFreeOOP->object = nil;    /* terminate the free list nicely */
  828.   }
  829.  
  830.   setSpaceInfo(objectDataSize);
  831.   ovp->ptr = objPtr;
  832. }
  833.  
  834. static void loadCharOOPs(imageFile)
  835. FILE    *imageFile;
  836. {
  837.   int        i;
  838.  
  839.   fread(charObjectTable, sizeof(CharObject), NUM_CHAR_OBJECTS, imageFile);
  840.  
  841.   for (i = 0; i < NUM_CHAR_OBJECTS; i++) {
  842.     oopTable[i + CHAR_OBJECT_BASE].object = (Object)&charObjectTable[i];
  843.     oopTable[i + CHAR_OBJECT_BASE].inSpace = toSpace;
  844.     charObjectTable[i].objClass = fromRelative(charObjectTable[i].objClass);
  845.   }
  846. }
  847.  
  848. static void loadSpecialOOPs(imageFile)
  849. FILE    *imageFile;
  850. {
  851.   fread(&nilObject, sizeof(struct NilObjectStruct), 1, imageFile);
  852.   nilOOP->object = (Object)&nilObject;
  853.   nilOOP->object->objClass = fromRelative(nilOOP->object->objClass);
  854.   nilOOP->inSpace = toSpace;
  855.  
  856.   fread(booleanObjects, sizeof(struct BooleanObjectStruct), 2, imageFile);
  857.   trueOOP->object = (Object)&booleanObjects[0];
  858.   falseOOP->object = (Object)&booleanObjects[1];
  859.   trueOOP->object->objClass = fromRelative(trueOOP->object->objClass);
  860.   falseOOP->object->objClass = fromRelative(falseOOP->object->objClass);
  861.   trueOOP->inSpace = falseOOP->inSpace = toSpace;
  862. }
  863.  
  864. static void fixupInstanceVars(ovp)
  865. OOPVector *ovp;
  866. {
  867.   int        i;
  868.   OOP        oop;
  869.  
  870.   for (i = 0; i < TOTAL_OOP_TABLE_SLOTS; i++) {
  871.     oop = oopAt(i);
  872.     if (oopValid(oop)) {
  873.       fixupOOPInstanceVars(oop, ovp);
  874.     }
  875.   }
  876. }
  877.  
  878. static void fixupOOPInstanceVars(oop, ovp)
  879. OOP    oop;
  880. OOPVector *ovp;
  881. {
  882.   int        numFixed, numIndexed;
  883.   Boolean    hasPointers;
  884.  
  885.   hasPointers = isPointers(oop);
  886.   numFixed = oopFixedFields(oop);
  887.   numIndexed = numIndexableFields(oop);
  888.   restoreInstanceVars(oop, hasPointers, numFixed, numIndexed);
  889. }
  890.  
  891.  
  892.